package com.example.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

public final class EchoServer {
	private int port;

	public EchoServer(int port) {
		this.port = port;
	}

	public static void main(String[] args) throws Exception {
		int port;
		if (args.length > 0) {
			port = Integer.parseInt(args[0]);
		} else {
			port = 8089;
		}

		new EchoServer(port).run();
	}

	public void run() throws Exception {
		EventLoopGroup bossGroup = new NioEventLoopGroup();
		EventLoopGroup workerGroup = new NioEventLoopGroup();
		try {
			ServerBootstrap bootstrap = new ServerBootstrap();
			// The handler specified here will always be evaluated by a newly
			// accepted Channel. The ChannelInitializer is a special handler
			// that is purposed to help a user configure a new Channel. It is
			// most likely that you want to configure the ChannelPipeline of the
			// new Channel by adding some handlers such as DiscardServerHandler
			// to implement your network application. As the application gets
			// complicated, it is likely that you will add more handlers to the
			// pipeline and extract this anonymous class into a top level class
			// eventually.
			bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
					.option(ChannelOption.SO_BACKLOG, 100).handler(new LoggingHandler(LogLevel.INFO))
					.childHandler(new ChannelInitializer<SocketChannel>() {

						@Override
						protected void initChannel(SocketChannel ch) throws Exception {
							// TODO Auto-generated method stub
							ch.pipeline().addLast(new EchoServerHandler());
						}

					});

			ChannelFuture future = bootstrap.bind(port).sync();
			System.out.println("Echo Server Start");

			// wait until the server socket is closed.
			// In this example, this does not happen, but you can do that to
			// gracefully
			// shut down you server.
			future.channel().closeFuture().sync();

		} finally {
			// TODO: handle finally clause
			workerGroup.shutdownGracefully();
			bossGroup.shutdownGracefully();
			System.out.println("Server Exit");
		}
	}

}
